package com.alks.common.aspect;

import com.alks.common.aop.RoleCheck;
import com.alks.common.data.dto.SysUserTokenDTO;
import com.alks.common.data.enums.system.LoginIgnoreEnum;
import com.alks.common.data.thread.UserIdThread;
import com.alks.common.utils.beanutils.ArrayUtils;
import com.alks.entity.exception.TokenErrorException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

@Aspect
@Component
@Slf4j
public class RoleCheckAspect {

    /**
     * 无权限抛出异常
     *
     * @param joinPoint
     * @throws TokenErrorException
     */
    @Before("@within(com.alks.common.aop.RoleCheck)")
    public void beforeInvoke(JoinPoint joinPoint) throws TokenErrorException {
        /*获取方法名*/
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        String methodName = methodSignature.getMethod().getName();
        // 获取目标类
        Class<?> targetClass = joinPoint.getSignature().getDeclaringType();
        // 获取目标类上的RoleCheck注解
        RoleCheck roleAnnotation = targetClass.getAnnotation(RoleCheck.class);
        if (roleAnnotation != null) {
            /*忽略指定方法*/
            Set<String> methodSet = Arrays.stream(roleAnnotation.methodName()).collect(Collectors.toSet());
            if (LoginIgnoreEnum.IgnoreExist(UserIdThread.get().getLoginName())){
                log.debug("超级用户登录：{}", targetClass.getName());
                return;
            }
            if (methodSet.contains(methodName)) {
                log.debug("鉴权已忽略目标方法：{}", methodName);
                return;
            }
            /*获取用户信息*/
            SysUserTokenDTO sysUserTokenDTO = UserIdThread.get();   //获取用户信息
            String loginName = sysUserTokenDTO.getLoginName();      //用户姓名
            List<String> userPrgIds = sysUserTokenDTO.getPrgIds();    //用户拥有权限
            List<String> needPrgIds = Arrays.stream(roleAnnotation.prgIds()).collect(Collectors.toList());       //所需权限转化为list
            /*拥有任意权限之一即可访问*/
            if (ArrayUtils.isEmpyt(userPrgIds)) {
                log.warn("账号" + loginName + "权限异常（没有任何权限）");
                throw new TokenErrorException("账号" + loginName + "权限异常，请重新登录");
            }
            Collection<String> intersection = CollectionUtils.intersection(userPrgIds, needPrgIds);
            if (roleAnnotation.prgIds() != null && ArrayUtils.isEmpyt(intersection)) {
                log.warn("账号" + loginName + "无权访问" + targetClass.getName());
                throw new TokenErrorException("账号" + loginName + "无权访问" + targetClass.getName());
            }
        }
    }
}
